package model.map;

import model.entity.*;
import java.util.*;

public class DrawMapVisitor extends MapVisitor {
	private ViewMap viewMap;
	private Avatar avatar;
	
	/**
	 * Constructor for a DrawMapVisitor.
	 * @param avatar
	 * @param view
	 */
	public DrawMapVisitor(Avatar avatar, ViewMap view) {
		this.avatar = avatar;
		this.viewMap = view;
	}

	/**
	 * Passes the graphic data at the tile to the View Map
	 */
	public void visit(GameMap gameMap) {
		// get the boundary of the map
		MapPoint boundary = gameMap.getBoundary();
		int xDim = boundary.getXCoordinate();
		int yDim = boundary.getYCoordinate();
		
		// get the avatar's coordinates
		Avatar avatar = this.avatar;
		MapPoint centerLocation = avatar.getLocation();
		int xCenter = centerLocation.getXCoordinate();
		int yCenter = centerLocation.getYCoordinate();
		
		// get the avatar's range
		int range = avatar.getViewRange();
		
		// calculate the bounds of our query based on the the avatar's range
		int xHighBound = Math.min(xCenter + 2 * range + 2, xDim);
		int xLowBound = Math.max(xCenter - 2 * range - 2, 0);
		
		int yHighBound = Math.min(yCenter + range + 1, yDim);
		int yLowBound = Math.max(yCenter - range - 1, 0);
		
		// push all relevant tile data to the view map
		for(int i = xLowBound;i<=xHighBound;++i){
			for(int j = yLowBound;j<=yHighBound;++j){
				MapPoint test = new MapPoint(i,j);
				if(!MapPoint.isValidLocation(test))
					continue;
				// if it's within range, pull new graphics
				int distance = MapPoint.findDistance(centerLocation, test);
				if(distance <= range + 1){
					MapTileState state = gameMap.getTileState(test);
					if(state != null){
						viewMap.pushRenderablesToPoint(state.pullDataFromMap(), test);
						if(distance <= range)
							removeOldShroudedEntities(gameMap,test);
					}
				}
			}
		}
	}
	
	/**
	 * Removes the old graphics of shrouded entities once 
	 * they become visible again.
	 * @param gameMap
	 * @param point
	 */
	private void removeOldShroudedEntities(GameMap gameMap, MapPoint point){
		// get the entities on the specific tile and compare with the set
		// of shrouded entities
		List<Entity> entitiesOnTile = gameMap.getEntitiesOnTile(point);
		Set<Entity> entSet = getCurrentlyShroudedEntities().keySet();
		for(Entity ent : entitiesOnTile){
			// if we've found one that needs to be removed do this
			if(entSet.contains(ent)){
				Set<String> graphicSet = ent.getDirectionalGraphicsSet();
				MapPoint pointer = getCurrentlyShroudedEntities().remove(ent);
				viewMap.removeImageFromQueue(pointer, graphicSet);
			}
		}
	}

	/**
	 * Used when starting the game.  Files in all of the releveant tiles
	 * seen by the Avatar onto the ViewMap.
	 * @param gameMap
	 */
	public void flash(GameMap gameMap) {
		// get the boundary of the map
		MapPoint boundary = gameMap.getBoundary();
		int xDim = boundary.getXCoordinate();
		int yDim = boundary.getYCoordinate();
		
		// push all relevant tile data to the view map
		for(int i = 0;i<=xDim;++i){
			for(int j = 0;j<=yDim;++j){
				MapPoint test = new MapPoint(i,j);
				if(!MapPoint.isValidLocation(test))
					continue;
				MapTileState state = gameMap.getTileState(test);
				if(state != null){
					viewMap.pushRenderablesToPoint(state.pullDataFromMap(), test);
				}
			}
		}
	}
}
